/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package io;

import com.illposed.osc.OSCListener;
import com.illposed.osc.OSCMessage;
import com.illposed.osc.OSCPortIn;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import tal.drivechain.plugin.Channel;
import tal.drivechain.plugin.Module;
import tal.drivechain.variable.SetProperty.Flag;
import tal.drivechain.variable.types.ArrayType;
import tal.drivechain.variable.types.DataType;
import tal.drivechain.variable.Variable;

/**
 *
 * @author Main
 */
public class OSCIn extends Module implements OSCListener {
    private int port;
    private HashMap<String, Variable> addressVariable = new HashMap<String, Variable>();
    private List<String> addresses = new ArrayList<String>();
    private OSCPortIn receiver;

    public void acceptMessage(Date timestamp, OSCMessage msg) {
        if (!isRunning()) return;
        
        //check if address is recognized.
        Variable out = addressVariable.get(msg.getAddress());
        if (out!=null) {
            if (debugFlag) log("Received a recognized osc message.", MSG.DEBUG);
            //get and clear the array inside the variable.
            List<Object> array = ((List<Object>)out.getInternalValue());
            array.clear();
            
            //copy the arguments from the osc message to the array.
            int idx = 0;
            for (Object arg : msg.getArguments()) {
                if (arg instanceof Float)
                    arg = (Double)((Float)arg).doubleValue();

                array.add(arg);
                idx++;
            }
            
            if (infoFlag) log("Received " + out.toString(), MSG.INFO);
            
            //send the variable.
            sendToOutputs(out, -1);
        } 
    }

    public void setPort(Integer port) {
        this.port = port;
    } public Integer getPort() { return port; }

    public void setAddress(List<String> addresses, Flag flag) {
        System.out.println("addresses=" + addresses + " flag=" + flag);
        if (flag==Flag.REPLACE)
            this.addresses = addresses;
        else {
            for (String a : addresses) this.addresses.add(a);
        }

        addressVariable.clear();
        for (String address : this.addresses) {
            Variable var = new Variable(address, new ArrayType(DataType.VAR), new ArrayList<Object>(), true);
            addressVariable.put(address, var);
            if (receiver!=null) {
                if (infoFlag) log("registering address: " + address, MSG.INFO);
                receiver.addListener(address, this);
            }
        }
        
    } public List<String> getAddress() { return addresses; }

    @Override
    public void start() {
        super.start();
        try {
            receiver = new OSCPortIn(port);
            for (String address : addressVariable.keySet()) {
                if (infoFlag) log("registering address: " + address, MSG.INFO);
                receiver.addListener(address, this);
            }
            receiver.startListening();
            log("Listening for OSC messages on port " + port, MSG.ANOUNCE);
        } catch (SocketException ex) {
            throw new IllegalArgumentException("Error while opening socket: " + ex.getMessage());
        }
    }

    @Override
    public void stop() {
        receiver.stopListening();
        receiver.close();
        receiver = null;
        super.stop();
    }

    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {
    }
}
